package com.tracelog.core.aspect;

import com.tracelog.core.annotation.TraceLog;
import com.tracelog.core.dao.LogRecordDao;
import com.tracelog.core.handler.LogHandler;
import com.tracelog.core.model.LogRecord;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.time.Instant;

/**
 * 日志切面
 *
 * @author tracelog
 * @since 1.0.0
 */
@Slf4j
@Aspect
@RequiredArgsConstructor
public class TraceLogAspect {

    private final LogHandler logHandler;
    private final LogRecordDao logRecordDao;

    /**
     * 切点 - 匹配TraceLog注解
     */
    @Pointcut("@annotation(com.tracelog.core.annotation.TraceLog) || @within(com.tracelog.core.annotation.TraceLog)")
    public void traceLogPointcut() {
    }

    /**
     * 环绕通知处理
     *
     * @param joinPoint 切点
     * @return 返回结果
     * @throws Throwable 异常
     */
    @Around("traceLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取目标方法
        Method method = getMethod(joinPoint);
        Class<?> targetClass = joinPoint.getTarget().getClass();
        
        // 判断是否需要记录日志
        if (!logHandler.shouldLog(method, targetClass)) {
            return joinPoint.proceed();
        }
        
        // 创建日志记录
        LogRecord logRecord = logHandler.createLogRecord(method, targetClass);
        
        // 记录请求信息
        logHandler.processRequestInfo(logRecord);
        
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 记录响应信息
            logHandler.processResponseInfo(logRecord, result);
            
            // 完成日志记录
            logRecord.complete(Instant.now());
            
            // 保存日志记录
            logRecordDao.save(logRecord);
            
            return result;
        } catch (Throwable e) {
            // 记录异常信息
            logHandler.processExceptionInfo(logRecord, e);
            
            // 完成日志记录
            logRecord.complete(Instant.now());
            
            // 保存日志记录
            logRecordDao.save(logRecord);
            
            throw e;
        }
    }

    /**
     * 获取目标方法
     *
     * @param joinPoint 切点
     * @return 方法
     */
    private Method getMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        return signature.getMethod();
    }
} 